# -*- mode: python -*-
###
#
# (c) 2000-2007 Wijnand Modderman <wijnand at tehmaze dot com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#     this list of conditions, and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions, and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   * Neither the name of the author of this software nor the name of
#     contributors to this software may be used to endorse or promote products
#     derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###

# system imports
import sys
import re
import time
import calendar
import popen2
import sgmllib

# DDB imports
from ddb.log import log

# common regular expressions
_re_date = re.compile('((?:[012]?\d)[\-/](?:[01]?\d)[\-/](?:\d{2,4}))')
_re_time = re.compile('((?:[01]?[0-9]|[2][0-3]):(?:[0-5][0-9])(?::[0-5][0-9])?)')

# units
_unitSizes = {
    'bytes':      {
        'step':     1024,
        'suffix':   ['B', 'kB', 'MB', 'GB', 'TB']
        },
    'meters':     {
        'step':     10,
        'suffix':   ['m', 'hm', 'km']
        },
    'milimeters': {
        'step':     10,
        'suffix':   ['mm', 'cm', 'dm', 'm', 'km', 'Mm']
        }
    }

class NotImplementedException(Exception):
    pass

def localImport(name):
    module     = __import__(name)
    components = name.split('.')
    for component in components[1:]:
        module = getattr(module, component)
    return module

def syntaxonly(doc):
    """Get the syntax line from the docstring."""
    doc = doc.splitlines()
    return doc[0]

def syntax(name = None):
    """Get the docstring from the calling function, and format it pretty."""
    frame = sys._getframe(1)
    try:
        if not name:
            name = frame.f_code.co_name
        doc  = frame.f_code.co_consts[0].splitlines()
        return '%s %s' % (name, doc[0])
    finally:
        del frame

def humanSize(units, size_in_bytes):
    step     = _unitSizes[units]['step']
    suffixes = _unitSizes[units]['suffix']
    devide = 1
    for x in range(0, len(suffixes)):
        if size_in_bytes >= (step**x):
            suffix = suffixes[x]
            devide = step**x
        else:
            break
    return '%.02f %s' % (float(size_in_bytes)/float(devide), suffix)

def normalize(text):
    """Normalize a text."""
    #text = text.encode('ISO-8859-1', 'replace')
    text = text.expandtabs()
    while '  ' in text:
        text = text.replace('  ', ' ')
    return text

class _stripHtml(sgmllib.SGMLParser):
    """HTML stripper."""

    def __init__(self):
        sgmllib.SGMLParser.__init__(self)

    def strip(self, data):
        """Strip HTML."""
        self.theString = ''
        self.feed(data)
        self.close()
        return self.theString

    def handle_data(self, data):
        self.theString += data

def stripHtml(html):
    """Strip HTML from input."""
    stripper = _stripHtml()
    return stripper.strip(html)

# trace decorator, adds a nice stack trace to your method call 
def trace(f):
    def newf(*args, **kw):
        print "calling %s with args %s, %s" % (f.__name__, args, kw)
        return f(*args, **kw)
    newf.__name__ = f.__name__
    newf.__dict__ = f.__dict__
    newf.__doc__ = f.__doc__
    newf.__module__ = f.__module__
    return newf

def shell(cmd):
    (r, w, e) = popen2.popen3(cmd)
    a = e.readlines()
    e.close()
    if a:
        w.close()
        r.close()
        raise Exception, a
    else:
        o = ''.join(r.readlines())
        r.close()
        w.close()
        return o

def strtotime(str):
    str = str.strip()
    if str[0] == '+':
        add = True
        str = str[1:]
    else:
        add = False
    times = _re_time.findall(str)
    dates = _re_date.findall(str)
    tests = {'time': None, 'date': None}
    if len(times) == 1:
        try:
            currtime = times[0]
            parts = [int(x) for x in currtime.split(':')]
            if len(parts) == 2:
                parts.append(0)
            year   = int(time.strftime('%Y'))
            month  = int(time.strftime('%m'))
            day    = int(time.strftime('%d'))
            if add:
                hour   = int(time.strftime('%H')) + int(parts[0])
                minute = int(time.strftime('%M')) + int(parts[1])
                second = int(time.strftime('%S')) + int(parts[2])
                while second > 60:
                    minute += 1
                    second -= 60
                while minute > 60:
                    hour   += 1
                    minute -= 60
                while hour > 24:
                    day    += 1
                    hour   -= 24
                while day > calendar.monthrange(year, month)[1]:
                    month  += 1
                    day    -= calendar.monthrange(year, month)[1]
                while month > 12:
                    year   += 1
                    month  -= 12
                tests['time'] = datetime.datetime(year, month, day, hour, minute, second)
            else:
                tests['time'] = datetime.datetime(year, month, day, parts[0], parts[1], parts[2])
        except ValueError, e:
            raise ValueError('bogus time string detected, accepted format: HH:MM[:SS]')
    if len(dates) == 1:
        currdate = dates[0].replace('/', '-')
        try:
            parts = [int(x) for x in currdate.split('-')]
            if parts[2] < 99:
                year = (int(time.strftime('%Y', time.time())) / 100) * 100
                parts[2] += year
            tests['date'] = datetime.datetime(parts[2], parts[1], parts[0])
        except ValueError, e:
            raise ValueError('bogus date string detected, accepted format: DD-MM-YY[YY]')
    if not tests['time'] and not tests['date']:
        # no valid date/time data found
        raise ValueError('no valid time or date found')
    elif (tests['time'] and not tests['date']):
        return tests['time']
    elif (tests['date'] and not tests['time']):
        # either one of the date/time data found
        return tests['date']
    else:
        # both date and time data found
        if add:
            raise ValueError('can not add date values, only time values')
        return datetime.datetime(
            tests['date'].year,
            tests['date'].month,
            tests['date'].day,
            tests['time'].hour,
            tests['time'].minute,
            tests['time'].second)

# vim:ts=4:sw=4:et:
